# -*- coding: utf-8 -*-
'''
    :file: __init__.py
    :author: -Farmer
    :url: https://blog.farmer233.top
    :date: 2021/02/10 01:43:02
'''
# import base（导入基本包）
from sqlalchemy.ext.declarative import api
from sqlalchemy.sql.expression import false, true
from app.models import LogMsg, User
import os
import shutil
import click
from flask import Flask, g
from flask.globals import current_app, request
# 导入模型
from app.forms.auth import RegisterForm
# 导入扩展
from app.extensions import db, auth, mail, cors, scheduler, marshmallow
# 导入配置
from app.settings import config
# 导入蓝图
from app.blueprints.test import test_bp
from app.blueprints.auth import auth_bp
from app.blueprints.cloud import cloud_bp
from app.blueprints.download import download_bp
from app.blueprints.admin import admin_bp

# 利用工厂模式，组装Flask实例(app)
def create_app(config_name=None):
    if config_name is None:
        config_name = os.getenv('FLASK_CONFIG', 'development')
    
    app = Flask(__name__)
    app.config.from_object(config[config_name])

    register_extensions(app)
    register_hooks(app)
    register_blueprints(app)
    register_commands(app)
    register_errors(app)

    return app

# 注册扩展
def register_extensions(app:Flask):
    db.init_app(app)
    mail.init_app(app)
    cors.init_app(app)
    scheduler.init_app(app)
    marshmallow.init_app(app)

# 注册蓝图
def register_blueprints(app:Flask):
    app.register_blueprint(test_bp, url_prefix="/test")
    app.register_blueprint(auth_bp, url_prefix="/auth")
    app.register_blueprint(cloud_bp, url_prefix="/cloud")
    app.register_blueprint(download_bp, url_prefix='/download')
    app.register_blueprint(admin_bp, url_prefix='/admin')

# 注册错误处理
def register_errors(app):
    """
    @description: 注册错误处理
    ---------
    @param: app:Flask
    -------
    @Returns: None
    -------
    """
    @app.errorhandler(400)
    def bad_request(e):
        pass
    
    @app.errorhandler(404)
    def page_not_found(e):
        return "服务器搬家了"

    @app.errorhandler(500)
    def internal_server_error(e):
        pass

# 注册命令行
def register_commands(app:Flask):
    # 导入模型
    from app.models import User
    # 注册初始化数据库命令（测试用）
    @app.cli.command()
    @click.option('--drop', is_flag=True, help='Create after drop.')
    def initdb(drop):
        db.create_all()
        click.echo("Initialized database.")

    # 注册系统初始化命令 flask init
    @app.cli.command()
    @click.option("--email", prompt=True, help="The username used to login.")
    @click.option("--username", prompt=True, help="The username used to login.")
    @click.option("--password", prompt=True, hide_input=True, help="The password used to login.")
    @click.option("--address", help="The username used to login.")
    def init(email, username, password, address):
        if not os.path.exists(app.config['UPLOAD_FOLDER']):
                os.mkdir(app.config['UPLOAD_FOLDER'])
                click.echo('创建物理存储路径完成')
        click.echo("正在初始化数据库.")
        db.create_all()
        admin = User.query.first()
        guest = User.query.filter(User.username == 'guest').first()

        try:
            if admin is not None:
                click.echo('The administrator already exists, updating...')
                admin.address = address
                admin.email = email
                admin.username = username
                admin.set_password(password)
            else:
                click.echo('Creating the temporary administrator account...')
                admin = RegisterForm(address = address)
                admin.set_admin(username=username, password=password, email=email, power=9)
                db.session.add(admin)
            if guest is not None:
                click.echo('The guest already exists, updating...')
                guest.address = address
                guest.email = email
                guest.username = username
                guest.set_password(password)
            else:
                click.echo('Creating the temporary guest account...')
                guest = RegisterForm(address = address)
                guest.set_email(email=email)
                guest.set_username(username='guest')
                guest.set_password(password=password)
                db.session.add(guest)

            db.session.commit()
        except ValueError as e:
            click.echo(e)
        click.echo('Done.')
    
    # 注册创建数据库命令
    @app.cli.command()
    def create():
        db.create_all()
        click.echo("Initialized database.")
        
    # 注册删库命令
    @app.cli.command()
    def drop():
        click.echo('正在删库，请尽快跑路')
        try:
            db.drop_all()
            shutil.rmtree(app.config['UPLOAD_FOLDER'])
        except Exception as e:
            click.echo(e)
        click.echo('删库完成')


# 注册日志
def register_logging(app):
    # sys log
    pass

# 注册钩子
def register_hooks(app:Flask):
    @app.teardown_request
    def teardown_request(e):
        # 在每个响应发送的时候记录下，形成系统日志
        user = g.get('user')
        username = 'Guest'
        is_admin = False
        if not user is None:
            user = User.query.get(user)
            username = user.username
            if user.power != 0:
                is_admin = True
        # 获取请求来源的 host 和 port
        host, port = request.host.split(":")
        host = request.remote_addr
        # 请求的接口url
        api_msg = request.full_path
        # 操作分类（访客等级0，注册用户等级5，管理员9)
        ctr_lv = 0
        if 'admin' in api_msg:
            ctr_lv = 9
        elif not user  is None:
            ctr_lv = 5
        try:
            log = LogMsg()
            log.username = username
            log.host = host
            log.port = port
            log.api_msg = api_msg
            log.ctr_lv = ctr_lv
            log.is_admin = is_admin
            db.session.add(log)
            db.session.commit()
        except Exception as err:
            app.logger.warning(err)
            app.logger.error(e)